//
//  ContentView.swift
//  Notepad
//
//  Created by jerry on 2025/8/16.
//

import SwiftUI
import Combine
import Foundation

struct ContentView: View {
    // 文件处理相关状态
    @State private var text: String = ""
    @State private var fileURL: URL? = nil
    @State private var fileName: String = "未命名"
    @State private var isLoading: Bool = false
    @State private var loadingProgress: Double = 0
    @State private var isEdited: Bool = false
    @State private var lineCount: Int = 0
    
    // 通知观察者
    @State private var notificationObservers: [NSObjectProtocol] = []
    
    // 搜索相关状态
    @State private var searchText: String = ""
    @State private var showSearchBar: Bool = false
    @State private var searchResults: [SearchResult] = []
    @State private var selectedResultIndex: Int? = nil
    
    var body: some View {
        VStack(spacing: 0) {
            // 工具栏
            toolbar
            
            // 搜索栏
            if showSearchBar {
                searchBar
            }
            
            // 主内容区域
            ZStack {
                if isLoading {
                    loadingView
                } else {
                    textEditorView
                }
            }
        }
        .onAppear {
            // 设置默认窗口大小
            if let window = NSApplication.shared.windows.first {
                window.setContentSize(NSSize(width: 800, height: 600))
            }
            
            // 设置通知观察者
            setupNotificationObservers()
        }
        .onDisappear {
            // 移除通知观察者
            removeNotificationObservers()
        }
    }
    
    // MARK: - 子视图
    
    // 工具栏
    private var toolbar: some View {
        HStack {
            Button(action: newDocument) {
                Image(systemName: "doc")
                    .frame(width: 40, height: 30)
            }
            .help("新建文档")
            
            Button(action: openDocument) {
                Image(systemName: "folder")
                    .frame(width: 40, height: 30)
            }
            .help("打开文档")
            
            Button(action: saveDocument) {
                Image(systemName: "arrow.down.doc")
                    .frame(width: 40, height: 30)
            }
            .help("保存文档")
            .disabled(fileURL == nil || !isEdited)
            
            Divider()
                .frame(height: 20)
            
            Button(action: toggleSearch) {
                Image(systemName: "magnifyingglass")
                    .frame(width: 40, height: 30)
            }
            .help("搜索")
            
            Spacer()
            
            // 文件信息
            Text("\(fileName)\(isEdited ? " *" : "") - \(lineCount) 行")
                .font(.system(size: 12))
                .foregroundColor(.gray)
        }
        .padding(.horizontal)
        .padding(.vertical, 8)
        .background(Color(NSColor.windowBackgroundColor))
    }
    
    // 搜索栏
    private var searchBar: some View {
        HStack {
            Image(systemName: "magnifyingglass")
                .foregroundColor(.gray)
            
            TextField("搜索", text: $searchText)
                .textFieldStyle(PlainTextFieldStyle())
                .onSubmit {
                    performSearch()
                }
            
            if !searchText.isEmpty {
                Button(action: {
                    searchText = ""
                    searchResults = []
                    selectedResultIndex = nil
                }) {
                    Image(systemName: "xmark.circle.fill")
                        .foregroundColor(.gray)
                }
                .buttonStyle(PlainButtonStyle())
            }
            
            if !searchResults.isEmpty {
                Text("\(selectedResultIndex != nil ? selectedResultIndex! + 1 : 0)/\(searchResults.count)")
                    .font(.caption)
                    .foregroundColor(.gray)
                
                Button(action: previousSearchResult) {
                    Image(systemName: "chevron.up")
                        .foregroundColor(.gray)
                }
                .buttonStyle(PlainButtonStyle())
                .disabled(searchResults.isEmpty || selectedResultIndex == nil || selectedResultIndex! <= 0)
                
                Button(action: nextSearchResult) {
                    Image(systemName: "chevron.down")
                        .foregroundColor(.gray)
                }
                .buttonStyle(PlainButtonStyle())
                .disabled(searchResults.isEmpty || selectedResultIndex == nil || selectedResultIndex! >= searchResults.count - 1)
            }
        }
        .padding(.horizontal)
        .padding(.vertical, 8)
        .background(Color(NSColor.controlBackgroundColor))
    }
    
    // 加载视图
    private var loadingView: some View {
        VStack {
            ProgressView(value: loadingProgress, total: 1.0)
                .frame(width: 200)
                .padding()
            
            Text("正在加载文件... \(Int(loadingProgress * 100))%")
                .font(.headline)
        }
    }
    
    // 文本编辑器视图
    private var textEditorView: some View {
        TextEditor(text: $text)
            .font(.system(size: 14, design: .monospaced))
            .onChange(of: text) { oldValue, newValue in
                isEdited = true
                updateLineCount()
                
                if !searchText.isEmpty {
                    performSearch()
                }
            }
            .overlay(
                // 高亮搜索结果
                GeometryReader { geometry in
                    ForEach(searchResults.indices, id: \.self) { index in
                        let result = searchResults[index]
                        Rectangle()
                            .fill(index == selectedResultIndex ? Color.yellow.opacity(0.5) : Color.yellow.opacity(0.3))
                            .frame(height: 16)
                            .position(calculatePositionForResult(result, in: geometry))
                    }
                }
                .allowsHitTesting(false)
            )
    }
    
    // MARK: - 通知处理
    
    // 设置通知观察者
    private func setupNotificationObservers() {
        let center = NotificationCenter.default
        
        // 新建文档
        let newObserver = center.addObserver(forName: .newDocument, object: nil, queue: .main) { _ in
            self.newDocument()
        }
        
        // 打开文档
        let openObserver = center.addObserver(forName: .openDocument, object: nil, queue: .main) { _ in
            self.openDocument()
        }
        
        // 保存文档
        let saveObserver = center.addObserver(forName: .saveDocument, object: nil, queue: .main) { _ in
            self.saveDocument()
        }
        
        // 另存为
        let saveAsObserver = center.addObserver(forName: .saveDocumentAs, object: nil, queue: .main) { _ in
            self.saveDocumentAs()
        }
        
        // 切换搜索
        let toggleSearchObserver = center.addObserver(forName: .toggleSearch, object: nil, queue: .main) { _ in
            self.toggleSearch()
        }
        
        // 查找下一个
        let findNextObserver = center.addObserver(forName: .findNext, object: nil, queue: .main) { _ in
            self.nextSearchResult()
        }
        
        // 查找上一个
        let findPrevObserver = center.addObserver(forName: .findPrevious, object: nil, queue: .main) { _ in
            self.previousSearchResult()
        }
        
        // 保存所有观察者以便后续移除
        notificationObservers = [
            newObserver,
            openObserver,
            saveObserver,
            saveAsObserver,
            toggleSearchObserver,
            findNextObserver,
            findPrevObserver
        ]
    }
    
    // 移除通知观察者
    private func removeNotificationObservers() {
        let center = NotificationCenter.default
        for observer in notificationObservers {
            center.removeObserver(observer)
        }
        notificationObservers = []
    }
    
    // MARK: - 文件操作
    
    // 新建文档
    private func newDocument() {
        if isEdited {
            // 在实际应用中，这里应该弹出确认对话框
        }
        
        text = ""
        fileURL = nil
        fileName = "未命名"
        isEdited = false
        updateLineCount()
    }
    
    // 打开文档
    private func openDocument() {
        let panel = NSOpenPanel()
        panel.allowsMultipleSelection = false
        panel.canChooseDirectories = false
        panel.canChooseFiles = true
        panel.allowedContentTypes = [.plainText]
        
        panel.begin { response in
            if response == .OK, let url = panel.url {
                self.loadFile(from: url)
            }
        }
    }
    
    // 加载文件
    private func loadFile(from url: URL) {
        isLoading = true
        loadingProgress = 0
        
        // 在后台线程加载文件
        DispatchQueue.global(qos: .userInitiated).async {
            do {
                // 获取文件大小
                let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path)
                let fileSize = fileAttributes[.size] as? Int64 ?? 0
                
                // 如果文件太大，使用流式处理
                if fileSize > 10_000_000 { // 10MB
                    self.loadLargeFile(from: url)
                } else {
                    self.loadSmallFile(from: url)
                }
            } catch {
                DispatchQueue.main.async {
                    self.isLoading = false
                    // 在实际应用中，这里应该显示错误提示
                    print("Error loading file: \(error)")
                }
            }
        }
    }
    
    // 加载小文件（一次性读取）
    private func loadSmallFile(from url: URL) {
        do {
            let content = try String(contentsOf: url)
            
            DispatchQueue.main.async {
                self.text = content
                self.fileURL = url
                self.fileName = url.lastPathComponent
                self.isEdited = false
                self.isLoading = false
                self.updateLineCount()
            }
        } catch {
            DispatchQueue.main.async {
                self.isLoading = false
                // 在实际应用中，这里应该显示错误提示
                print("Error reading file: \(error)")
            }
        }
    }
    
    // 加载大文件（流式处理）
    private func loadLargeFile(from url: URL) {
        do {
            let fileHandle = try FileHandle(forReadingFrom: url)
            var content = ""
            var buffer = Data()
            var bytesRead = 0
            let chunkSize = 1024 * 1024 // 1MB
            
            // 获取文件大小
            let fileSize = try FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int64 ?? 0
            
            // 分块读取文件
            while let chunk = try fileHandle.read(upToCount: chunkSize) {
                if chunk.isEmpty { break }
                
                buffer.append(chunk)
                bytesRead += chunk.count
                
                // 更新进度
                let progress = Double(bytesRead) / Double(fileSize)
                DispatchQueue.main.async {
                    self.loadingProgress = progress
                }
                
                // 处理完整块
                if let text = String(data: buffer, encoding: .utf8) {
                    content += text
                    buffer = Data()
                }
            }
            
            try fileHandle.close()
            
            DispatchQueue.main.async {
                self.text = content
                self.fileURL = url
                self.fileName = url.lastPathComponent
                self.isEdited = false
                self.isLoading = false
                self.updateLineCount()
            }
        } catch {
            DispatchQueue.main.async {
                self.isLoading = false
                // 在实际应用中，这里应该显示错误提示
                print("Error loading file: \(error)")
            }
        }
    }
    
    // 更新行数统计
    private func updateLineCount() {
        lineCount = text.components(separatedBy: .newlines).count
    }
    
    // 保存文档
    private func saveDocument() {
        if let url = fileURL {
            saveFile(to: url)
        } else {
            saveDocumentAs()
        }
    }
    
    // 另存为
    private func saveDocumentAs() {
        let panel = NSSavePanel()
        panel.allowedContentTypes = [.plainText]
        panel.nameFieldStringValue = fileName
        
        panel.begin { response in
            if response == .OK, let url = panel.url {
                self.saveFile(to: url)
            }
        }
    }
    
    // 保存文件到指定URL
    private func saveFile(to url: URL) {
        do {
            try text.write(to: url, atomically: true, encoding: .utf8)
            fileURL = url
            fileName = url.lastPathComponent
            isEdited = false
        } catch {
            // 在实际应用中，这里应该显示错误提示
            print("Error saving file: \(error)")
        }
    }
    
    // MARK: - 搜索功能
    
    // 切换搜索栏显示
    private func toggleSearch() {
        showSearchBar.toggle()
        if showSearchBar && !searchText.isEmpty {
            performSearch()
        }
    }
    
    // 执行搜索
    private func performSearch() {
        guard !searchText.isEmpty else {
            searchResults = []
            selectedResultIndex = nil
            return
        }
        
        var results: [SearchResult] = []
        var searchRange = text.startIndex..<text.endIndex
        
        while let range = text.range(of: searchText, options: [.caseInsensitive], range: searchRange) {
            results.append(SearchResult(range: range))
            searchRange = range.upperBound..<text.endIndex
        }
        
        searchResults = results
        selectedResultIndex = results.isEmpty ? nil : 0
        
        // 如果有搜索结果，滚动到第一个结果
        if let firstResult = searchResults.first {
            scrollToResult(firstResult)
        }
    }
    
    // 计算搜索结果在文本编辑器中的位置
    private func calculatePositionForResult(_ result: SearchResult, in geometry: GeometryProxy) -> CGPoint {
        // 这是一个简化的实现，实际应用中需要更精确的计算
        let totalChars = text.count
        if totalChars == 0 {
            return CGPoint(x: geometry.size.width / 2, y: geometry.size.height / 2)
        }
        
        let distance = text.distance(from: text.startIndex, to: result.range.lowerBound)
        let ratio = Double(distance) / Double(totalChars)
        return CGPoint(
            x: geometry.size.width / 2,
            y: geometry.size.height * CGFloat(ratio)
        )
    }
    
    // 滚动到指定的搜索结果
    private func scrollToResult(_ result: SearchResult) {
        // 在实际应用中，这里需要实现滚动到特定文本位置的逻辑
        // 由于SwiftUI的TextEditor不直接支持滚动到特定位置，
        // 这可能需要使用NSTextView的桥接或其他技术
    }
    
    // 下一个搜索结果
    private func nextSearchResult() {
        guard !searchResults.isEmpty, let current = selectedResultIndex else { return }
        let next = min(current + 1, searchResults.count - 1)
        selectedResultIndex = next
        scrollToResult(searchResults[next])
    }
    
    // 上一个搜索结果
    private func previousSearchResult() {
        guard !searchResults.isEmpty, let current = selectedResultIndex else { return }
        let prev = max(current - 1, 0)
        selectedResultIndex = prev
        scrollToResult(searchResults[prev])
    }
}

// 搜索结果模型
struct SearchResult {
    let range: Range<String.Index>
}

#Preview {
    ContentView()
}